﻿using GENERIC.Respository.Interfaces;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Configuration;
using System.Data.Objects;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Transactions;

namespace GENERIC.EFRepository
{
    public class EFContext : DbContext, IContext
    {
        #region Constructeur

        public EFContext(string connectionString, params Assembly[] assembliesToDiscover)
            : this(connectionString, null, assembliesToDiscover)
        {

        }

        public EFContext(string connectionString, string schemaName, params Assembly[]  assembliesToDiscover)
            : base(connectionString)
        {
            Assemblies = assembliesToDiscover;
            SchemaName = schemaName;
        }

        #endregion

        #region Properties

        private Assembly[] Assemblies { get; set; }

        /// <summary>
        /// Obtient l'ObjectContext sous-jacent
        /// </summary>
        private ObjectContext ObjectContext
        {
            get { return ((IObjectContextAdapter)this).ObjectContext; }
        }

        private string SchemaName { get; set; }

        #endregion

        #region Méthodes

        public IGENERICSet<TEntity> CreateSet<TEntity>() where TEntity : class, new()
        {
            return new EFSet<TEntity>(ObjectContext.CreateObjectSet<TEntity>());
        }

        public new void SaveChanges()
        {
            base.SaveChanges();
        }

        public ITransaction BeginTransaction()
        {
            return new Transaction();
        }

        /// <summary>
        /// Cette méthode est appelée pour initialiser le modèle du contexte qui est en train d'être créé.
        /// </summary>
        /// <param name="modelBuilder">le constructeur de modèle</param>
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            if (Assemblies != null)
            {
                foreach (var assembly in Assemblies)
                {
                    var typesToRegister = assembly.GetTypes().Where(type => type.IsSubclassOfGeneric(typeof(StructuralTypeConfiguration<>)));
                    var schemaName = SchemaName;
                    foreach (var type in typesToRegister)
                    {
                        if (type.IsAbstract)
                        {
                            continue;
                        }
                        if (string.IsNullOrEmpty(schemaName))
                        {
                            dynamic configuration = Activator.CreateInstance(type);
                            modelBuilder.Configurations.Add(configuration);
                        }
                        else
                        {
                            dynamic configuration = Activator.CreateInstance(type, schemaName);
                            modelBuilder.Configurations.Add(configuration);
                        }
                    }
                }
            }
        }

        #endregion
    }
}
